/*Lex.cpp*/

#include <iostream>
#include <string.h>
#include <fstream>
#include <sstream>
#include <set>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

void Lex_Function(ifstream&);

int main(int argc, char const *argv[])
{
    ifstream file("ip.txt",ios::in);
    Lex_Function(file);
    return 0;
}

void Lex_Function(ifstream& file)
{
    ofstream tokens ("tokens.txt");
    string keywords_arr[] = {"auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "int", "long",  "register", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while"};
    set<string> keywords(keywords_arr, keywords_arr+sizeof(keywords_arr)/sizeof(keywords_arr[0]));

    string all_op_arr[] = {"&&", "||", "!", "+", "-", "*", "/", "%", "++", "--", "==", "!=", "<", ">", "<=", ">=", "&", "|", "^", "<<", ">>", "~", "="};
    set<string> all_op(all_op_arr, all_op_arr+sizeof(all_op_arr)/sizeof(all_op_arr[0]));
    set<string> logical_op(all_op_arr, all_op_arr+(size_t)3);                   //string logical_op_arr[] = {"&&","||","!"};
    set<string> arithmatic_op(all_op_arr+(size_t)3, all_op_arr+(size_t)10);     //string arithmetic_op_arr[] = {"+","-","*","/","%","++","--"};
    set<string> relational_op(all_op_arr+(size_t)10, all_op_arr+(size_t)16);   	//string relational_op_arr[] = {"==","!=","<",">","<=",">="};
    set<string> bitwise_op(all_op_arr+(size_t)16, all_op_arr+(size_t)22);   	//string bitwise_op_arr[] = {"&","|","^","<<",">>","~"};
    set<string> assignment_op(all_op_arr+(size_t)22, all_op_arr+(size_t)23);	//string assignment_op_arr[] = {"="};

    if (file.good())
    {
        string str;
        int MC_flag = 0;
        while(getline(file, str))
        {
            istringstream ss(str);
            int i=0, white_space=0, div_flag = 0;

            //tokens<<"input : "<<str<<endl;
            for(i=0; i<str.length();)
            {
                if(MC_flag == 0 && (((int)str[i] >= 65 && (int)str[i] <= 90) || ((int)str[i] >= 97 && (int)str[i] <= 122) || (int)str[i] == 61))
                {
                    string token;
                    while(((int)str[i] >= 65 && (int)str[i] <= 90) || ((int)str[i] >= 97 && (int)str[i] <= 127) || (int)str[i] == 95 || ((int)str[i] >= 48 && (int)str[i] <= 57))
                    {
                        token = token + str[i];
                        i++;
                    }
                    if((int)str[i] == 91)
                    {
                        tokens<<"Size of Array '"<<token<<"' : ";
                        i++;
                        while((int)str[i] != 93)
                        {
                            tokens<<str[i];
                            i++;
                        }
                        tokens<<endl;
                        i++;
                        tokens<<"Array variable : ";
                    }
                    else if(keywords.find(token) != keywords.end())
                    {
                        tokens<<"Keyword : ";
                    }
                    else
                    {
                        tokens<<"Identifier : ";
                    }
                    tokens<<token<<endl;
                }
                else if(MC_flag == 0 && (int)str[i] >= 48 && (int)str[i] <= 57)
                {
                    string token;
                    int flag=0;
                    while((int)str[i] >= 48 && (int)str[i] <= 57)
                    {
                        token = token + str[i];
                        i++;
                        if((int)str[i] == 46)
                        {
                            tokens<<"Float number : ";
                            flag = 1;
                            token = token + str[i];
                            i++;
                        }
                        if((int)str[i] == 69)
                        {
                            tokens<<"Exponential number : ";
                            flag = 2;
                            token = token + str[i];
                            i++;
                            if((int)str[i] == 45)
                            {
                                token = token + str[i];
                                i++;
                            }
                        }
                    }
                    if(flag == 0)
                    {
                        tokens<<"Integer number : ";
                    }
                    tokens<<token<<endl;
                }

                stringstream ss;
                ss << str[i];
                string token_op, next_token_op;
                ss >> token_op;
                stringstream ss1;
                ss1 << str[i+1];
                ss1 >> next_token_op;

                if(div_flag == 0 && (MC_flag == 1 || token_op.compare("/") == 0))
                {
                    if(MC_flag == 0 && next_token_op.compare("/") == 0)
                    {
                        tokens<<"Single Line Comment Found : "<<str<<endl;
                        i = i+str.length();
                    }
                    else if(MC_flag == 1 || next_token_op.compare("*") == 0)
                    {
                        if(MC_flag == 0)
                        {
                            MC_flag = 1;
                            tokens<<"Multi-Line Comment Found : "<<endl;
                            i = i+2;
                        }
                        int flag = 0;
                        while((int)str[i] != 42)
                        {
                            if((int)str[i] == 0)
                            {
                                tokens<<endl<<"Part of Multi-Line Comment"<<endl;
                                flag = 1;
                                break;
                            }
                            tokens<<str[i];
                            i++;
                        }
                        if(flag == 1)
                        {
                            flag = 0;
                            continue;
                        }
                        i=i+2;
                        MC_flag = 0;
                        tokens<<endl<<"End of Multi-Line Comment"<<endl;
                    }
                    else
                    {
                        div_flag = 1;
                    }
                }
                else if(div_flag == 1 || (MC_flag == 0 && all_op.find(token_op) != all_op.end()))
                {
                    div_flag = 0;
                    if(logical_op.find(token_op) != logical_op.end())
                    {
                        if(assignment_op.find(next_token_op) != assignment_op.end())
                        {
                            tokens<<"Relational Operator : "<<str[i]<<str[i+1]<<endl;
                            i++;
                        }
                        else if(logical_op.find(next_token_op) == logical_op.end())
                            tokens<<"Logical Operator : "<<str[i]<<endl;
                    }
                    else if(arithmatic_op.find(token_op) != arithmatic_op.end())
                    {
                        if(arithmatic_op.find(next_token_op) != arithmatic_op.end())
                        {
                            tokens<<"Arithmatic Operator : "<<str[i]<<str[i+1]<<endl;
                            i++;
                        }
                        else if(arithmatic_op.find(next_token_op) == arithmatic_op.end())
                            tokens<<"Arithmatic Operator : "<<str[i]<<endl;
                    }
                    else if(relational_op.find(token_op) != relational_op.end())
                    {
                        if(relational_op.find(next_token_op) != relational_op.end())
                        {
                            tokens<<"Bitwise Operator : "<<str[i]<<str[i+1]<<endl;
                            i++;
                        }
                        else if(assignment_op.find(next_token_op) != assignment_op.end())
                        {
                            tokens<<"Relational Operator : "<<str[i]<<str[i+1]<<endl;
                            i++;
                        }
                        else if(relational_op.find(next_token_op) == relational_op.end())
                            tokens<<"Relational Operator : "<<str[i]<<endl;
                    }
                    else if(bitwise_op.find(token_op) != bitwise_op.end())
                    {
                        if(bitwise_op.find(next_token_op) != bitwise_op.end())
                        {
                            tokens<<"Logical Operator : "<<str[i]<<str[i+1]<<endl;
                            i++;
                        }
                        else if(bitwise_op.find(next_token_op) == bitwise_op.end())
                            tokens<<"Bitwise Operator : "<<str[i]<<endl;
                    }
                    else if(assignment_op.find(token_op) != assignment_op.end())
                    {
                        if(assignment_op.find(next_token_op) != assignment_op.end())
                        {
                            tokens<<"Relational Operator : "<<str[i]<<str[i+1]<<endl;
                            i++;
                        }
                        else if(assignment_op.find(next_token_op) == assignment_op.end())
                            tokens<<"Assignment Operator : "<<str[i]<<endl;
                    }
                    i++;
                }
                else if(MC_flag == 0 && ((int)str[i] == 59))// || (int)str[i] == 44 || (int)str[i] == 58))
                {
                    tokens<<"Delimiter : "<<str[i]<<endl;
                    tokens<<"End : $"<<endl;
                    i++;
                }
                else if(MC_flag == 0 && ((int)str[i] == 40 || (int)str[i] == 41 || (int)str[i] == 123 || (int)str[i] == 125))
                {
                    tokens<<"Bracket : "<<str[i]<<endl;
                    i++;
                }
                else if(MC_flag == 0 && (int)str[i] == 35)
                {
                    string token, header_check = "include", macro_check = "define";
                    i++;
                    while((int)str[i] != 32)
                    {
                        token = token + str[i];
                        i++;
                    }
                    if(token.compare(header_check) == 0)
                    {
                        tokens<<"Header File : ";
                        i++;
                        if((int)str[i] == 60 || (int)str[i] == 34)
                        {
                            i++;
                            while((int)str[i] != 62 && (int)str[i] != 34)
                            {
                                tokens<<str[i];
                                i++;
                            }
                            i++;
                            tokens<<endl;
                        }
                    }
                    if(token.compare(macro_check) == 0)
                    {
                        tokens<<"Macro : ";
                        i++;
                        while((int)str[i] != 0)
                        {
                            tokens<<str[i];
                            i++;
                        }
                        tokens<<endl;
                    }
                }
                while((int)str[i] == 32)
                {
                    white_space++;
                    i++;
                }
            }
            //tokens<<"Number of blank spaces : "<<white_space<<endl;
            //tokens<<endl<<"--------------------------------------"<<endl<<endl;
        }
    }
    tokens.close();
}
